﻿# include "vd.h"
# include "VD_DeleteDevice.h"
# include "VD_FlushFileBuffer.h"
# include "VD_CheckFile.h"

#pragma code_seg()
VOID VD_ThreadHandler (
    IN PVOID Context)
{
    PDEVICE_OBJECT      device_object;
    PDEVICE_EXTENSION   device_extension;
    PLIST_ENTRY         request;
	PIRP                irp;
    PIO_STACK_LOCATION  io_stack;
    PULONG	            system_buffer;
	LARGE_INTEGER		ReadOffset;
	LARGE_INTEGER		WriteOffset;
	LONGLONG			i;
	NTSTATUS			status;   
	
	device_object = (PDEVICE_OBJECT) Context;

    device_extension = (PDEVICE_EXTENSION) device_object->DeviceExtension;	

    KeSetPriorityThread(KeGetCurrentThread(), LOW_REALTIME_PRIORITY);

   while (TRUE)
    {
	status = KeWaitForSingleObject(
								 &device_extension->request_event,
								 Executive,
								 KernelMode,
						         FALSE,
								 NULL
								  ); 
	 
	if (device_extension->terminate_thread)
	{
          
		DbgPrint("Terminating Thread... \n");
		PsTerminateSystemThread(STATUS_SUCCESS);
    }
    
    while (request = ExInterlockedRemoveHeadList(
											   &device_extension->list_head,
											   &device_extension->list_lock
												))
    {
		irp = CONTAINING_RECORD(request, IRP, Tail.Overlay.ListEntry);
        io_stack = IoGetCurrentIrpStackLocation(irp);
        switch (io_stack->MajorFunction)
        {
			case IRP_MJ_DEVICE_CONTROL:
					
			switch (io_stack->Parameters.DeviceIoControl.IoControlCode)
			{
				case IOCTL_VD_CHECK_FILE:
				{
				PVOID			RetVal;
				irp->IoStatus.Status = VD_CheckFile(device_object,irp);
				RetVal = irp->AssociatedIrp.SystemBuffer;
			
				RtlCopyMemory(RetVal,&device_extension->PasswordCheck,LONGSIZE);
				irp->IoStatus.Information  = LONGSIZE; 
				break;
				}
				
				case IOCTL_VD_OPEN_FILE:
				{
				irp->IoStatus.Status = VD_OpenFile(device_object, irp);
                break;
				}
				
				case IOCTL_VD_CLOSE_FILE:
				{
				irp->IoStatus.Status = VD_CloseFile(device_object, irp);
                break;
				}
			
                default:
                irp->IoStatus.Status = STATUS_DRIVER_INTERNAL_ERROR;
                }
                break;

				case IRP_MJ_READ:
				{ 
				PULONG				Char2Long;
				
				system_buffer = (PULONG) MmGetSystemAddressForMdlSafe(irp->MdlAddress, NormalPagePriority);
                
				if (system_buffer == NULL)
                {
					irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
                    irp->IoStatus.Information = 0;
                    break;
                }
               
				Char2Long = (PULONG) ExAllocatePoolWithTag(
														PagedPool, 
														io_stack->Parameters.Read.Length,
														POOL_TAG
														  );
				if (Char2Long == NULL)
                {
                    DbgPrint("Unable allocate intermediate buffer !!!\n");
					irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
                    irp->IoStatus.Information = 0;
                    break;
                }
				
				ReadOffset.QuadPart = io_stack->Parameters.Read.ByteOffset.QuadPart + PassOffset;
				 			
				ZwReadFile(
						 device_extension->file_handle,
						 NULL,
						 NULL,
						 NULL,
						 &irp->IoStatus,
						 Char2Long,
						 io_stack->Parameters.Read.Length,
						 &ReadOffset,
						 NULL
                    );
				
				if (irp->Flags & IRP_NOCACHE & IRP_PAGING_IO)
					DbgPrint("\t \t \t \t Read NonCached info!!!! \n"); 
				
				DbgPrint("Read Crypt \n");
				if (device_extension->IsDiskRaw || (!device_extension->IsDiskRaw && device_extension->PasswordCheck))
				{
					for (i = 0; i < io_stack->Parameters.Read.Length/LONGSIZE; i+=2)
					{
						VD_BF_Decrypt(&device_extension->ctx, &Char2Long[i],&Char2Long[i+1]);
					}
				}
				
				RtlCopyMemory(system_buffer, Char2Long, io_stack->Parameters.Read.Length);

				ExFreePoolWithTag(Char2Long,POOL_TAG);
               
				break;
				}
				
				case IRP_MJ_WRITE:
				{
				
				PULONG				Char2Long;
	
				WriteOffset.QuadPart = io_stack->Parameters.Write.ByteOffset.QuadPart + PassOffset;
					
				if ((WriteOffset.QuadPart + io_stack->Parameters.Write.Length) >
                     device_extension->file_size.QuadPart)
                {
                    DbgPrint("Write Buffer Error!!! \n");
					irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
                    irp->IoStatus.Information = 0;
                    break;
                }
				   
				Char2Long = (PULONG) ExAllocatePoolWithTag(
													PagedPool, 
													io_stack->Parameters.Write.Length,
													POOL_TAG
														);
				if (Char2Long == NULL)
                {
                    DbgPrint("Unable allocate intermediate buffer !!!\n");
					irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
                    irp->IoStatus.Information = 0;
                    break;
                }
		
				RtlCopyMemory( Char2Long,
					         (PULONG)MmGetSystemAddressForMdlSafe(irp->MdlAddress, NormalPagePriority),
								io_stack->Parameters.Write.Length,
							);  	
			
				DbgPrint("Write crypt \n");
				
				if (device_extension->IsDiskRaw || (!device_extension->IsDiskRaw && device_extension->PasswordCheck))
				{
					for (i = 0; i < io_stack->Parameters.Write.Length/LONGSIZE; i+=2)
					{
						VD_BF_Encrypt(&device_extension->ctx, &Char2Long [i],&Char2Long [i + 1]);
					}
				}
				
				ZwWriteFile(
						  device_extension->file_handle,
						  NULL,
						  NULL,
						  NULL,
						  &irp->IoStatus,
						  Char2Long,
						  io_stack->Parameters.Write.Length,
						  &WriteOffset,
						  NULL
							);
				
				ExFreePoolWithTag(Char2Long,POOL_TAG);
					
				
				if (irp->Flags & IRP_NOCACHE & IRP_PAGING_IO)
					DbgPrint("\t \t \t \t Write NonCached info!!!! \n");
				 
				
				if (!irp->Flags & IRP_NOCACHE){
					status = VD_FlushFileBuffer(device_extension->file_handle);
				}			
	
                break;
				}
				
            default:
                irp->IoStatus.Status = STATUS_DRIVER_INTERNAL_ERROR;
            }
			IoCompleteRequest(irp,
                (CCHAR) (NT_SUCCESS(irp->IoStatus.Status) ?
                IO_DISK_INCREMENT : IO_NO_INCREMENT)
                );
        }
    }
	
}
